﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

namespace CCU.Core.Channel
{
    public class ContextReceivalCallContextInitializer : ICallContextInitializer
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="correlationState"></param>
        public void AfterInvoke(object correlationState)
        {
            CCUChannelExtra context = correlationState as CCUChannelExtra;
            if (context == null)
            {
                return;
            }

            MessageHeader<CCUChannelExtra> contextHeader = new MessageHeader<CCUChannelExtra>(context);
            OperationContext.Current.OutgoingMessageHeaders.Add(
                contextHeader.GetUntypedHeader(CCUChannelExtra.callContextKey, CCUChannelExtra.contextHeaderNamespace)
                );
            CCUChannelExtra.GetEntity = null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="instanceContext"></param>
        /// <param name="channel"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
        {
            int n = message.Headers.FindHeader(CCUChannelExtra.callContextKey, CCUChannelExtra.contextHeaderNamespace);
            if (n == -1)
            {
                // 不符合规范的
                CCUChannelExtra.GetEntity.output = "error! Connection not allowed. can't find [CCUBehavior].";
                FaultException ex = new FaultException(new Exception(CCUChannelExtra.GetEntity.output).Message);
                Logger.Write(ex, channel);
                throw ex;
            }
            CCUChannelExtra context = null;

            try
            {
                context = message.Headers.GetHeader<CCUChannelExtra>(CCUChannelExtra.callContextKey, CCUChannelExtra.contextHeaderNamespace);
            }
            catch (Exception ex)
            {
                FaultException fex = new FaultException(ex.Message);
                Logger.Write(fex, channel);
                throw fex;
            }

            if (context == null) return null;
            CCUChannelExtra.GetEntity = context;

            // 验证数据
            if (!ChannelVerify.IsValidChannelInfo(context))
            {
                FaultException ex = new FaultException(new Exception(CCUChannelExtra.GetEntity.output).Message);
                Logger.Write(ex, channel);
                throw ex;
            }

            // IP限制验证
            string connectIP = CCUChannel.ConnectIP();
            if (!IpFilter.IsAllow(connectIP))
            {
                CCUChannelExtra.GetEntity.output = "error! IP is not allowed to connect CCU.";
                FaultException ex = new FaultException(new Exception(CCUChannelExtra.GetEntity.output + "IP is " + connectIP + ".").Message);
                Logger.Write(ex, channel);
                throw ex;
            }

            // 验证Channel Key
            if (!ChannelVerify.IsValidChannelKey(context.moduleKey))
            {
                CCUChannelExtra.GetEntity.output = "error! not a valid channel key.";
                FaultException ex = new FaultException(new Exception(CCUChannelExtra.GetEntity.output).Message);
                Logger.Write(ex, channel);
                throw ex;
            }

            // 是否匹配的代理商
            if (!ChannelVerify.IsValidAgent(context.gameZoneId))
            {
                CCUChannelExtra.GetEntity.output = "error! agent id does not match on ccu.";
                FaultException ex = new FaultException(new Exception(CCUChannelExtra.GetEntity.output).Message);
                Logger.Write(ex, channel);
                throw ex;
            }

            // 是否拥有连接该代理商CCU的权限
            if (!ChannelVerify.IsAllowAgent(context.gameZoneId))
            {
                CCUChannelExtra.GetEntity.output = "error! do not have permission at this agent.";
                FaultException ex = new FaultException(new Exception(CCUChannelExtra.GetEntity.output).Message);
                Logger.Write(ex, channel);
                throw ex;
            }

            return CCUChannelExtra.GetEntity;
        }
    }
}
